﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;

namespace LaserTag.Common.Controls
{
    public class AreaSelection : Control
    {
        private FrameworkElement m_selectionVisual;
        private FrameworkElement m_selectionArea;
        bool m_isDown;
        bool m_isDragging;
        bool m_selected = false;
        UIElement m_selectedElement = null;

        Point m_startPoint;
        private double m_originalLeft;
        private double m_originalTop;

        public AreaSelection()
        {
            Loaded += new RoutedEventHandler(AreaSelection_Loaded);
        }

        void AreaSelection_Loaded(object sender, RoutedEventArgs e)
        {
            SetupAdorners();
        }
        static AreaSelection()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(AreaSelection),
                                                     new FrameworkPropertyMetadata(typeof(AreaSelection)));
        }

        #region TargetAreaSize

        public static readonly DependencyProperty TargetAreaSizeProperty =
            DependencyProperty.Register("TargetAreaSize", typeof(Size), typeof(AreaSelection),
                                        new FrameworkPropertyMetadata(new Size(),
                                                                      new PropertyChangedCallback(OnTargetAreaSizeChanged)));

        private ResizingAdorner m_adorner;


        public Size TargetAreaSize
        {
            get { return (Size)GetValue(TargetAreaSizeProperty); }
            set { SetValue(TargetAreaSizeProperty, value); }
        }

        private static void OnTargetAreaSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((AreaSelection)d).OnTargetAreaSizeChanged(e);
        }

        protected virtual void OnTargetAreaSizeChanged(DependencyPropertyChangedEventArgs e)
        {
            SetSelectionAreaSize();
        }

        #endregion

        #region SelectionArea

        /// <summary>
        /// SelectionArea Dependency Property
        /// </summary>
        public static readonly DependencyProperty SelectionAreaProperty =
            DependencyProperty.Register("SelectionArea", typeof(Rect), typeof(AreaSelection),
                new FrameworkPropertyMetadata((Rect)Rect.Empty));

        /// <summary>
        /// Gets or sets the SelectionArea property.  This dependency property 
        /// indicates ....
        /// </summary>
        public Rect SelectionArea
        {
            get { return (Rect)GetValue(SelectionAreaProperty); }
            set { SetValue(SelectionAreaProperty, value); }
        }

        #endregion

        

        
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            m_selectionVisual = GetTemplateChild("PART_SelectionVisual") as FrameworkElement;
            m_selectionArea = GetTemplateChild("PART_SelectionArea") as FrameworkElement;
            SetSelectionAreaSize();
            SetupAdorners();
            SetupEventHandlers();
        }

        private void SetupEventHandlers()
        {
            //this.MouseLeftButtonDown += new MouseButtonEventHandler(Window1_MouseLeftButtonDown);
            //this.MouseLeftButtonUp += new MouseButtonEventHandler(DragFinishedMouseHandler);
            //this.MouseMove += new MouseEventHandler(MouseMoveHandler);
            //this.MouseLeave += new MouseEventHandler(Window1_MouseLeave);
            
            if(m_selectionArea == null)
                return;

            //m_selectionArea.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(myCanvas_PreviewMouseLeftButtonDown);
            //m_selectionArea.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(DragFinishedMouseHandler);
        }

        // Handler for drag stopping on leaving the window
        void Window1_MouseLeave(object sender, MouseEventArgs e)
        {
            StopDragging();
            e.Handled = true;
        }

        // Handler for drag stopping on user choise
        void DragFinishedMouseHandler(object sender, MouseButtonEventArgs e)
        {
            StopDragging();
            e.Handled = true;
        }

        // Method for stopping dragging
        private void StopDragging()
        {
            if (m_isDown)
            {
                m_isDown = false;
                m_isDragging = false;
            }
        }

        private void MouseMoveHandler(object sender, MouseEventArgs e)
        {
            if (m_selectionArea == null)
                return;

            if (m_isDown)
            {
                if ((m_isDragging == false) &&
                    ((Math.Abs(e.GetPosition(m_selectionArea).X - m_startPoint.X) > SystemParameters.MinimumHorizontalDragDistance) ||
                    (Math.Abs(e.GetPosition(m_selectionArea).Y - m_startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)))
                    m_isDragging = true;

                if (m_isDragging)
                {
                    Point position = Mouse.GetPosition(m_selectionArea);
                    Canvas.SetTop(m_selectedElement, position.Y - (m_startPoint.Y - m_originalTop));
                    Canvas.SetLeft(m_selectedElement, position.X - (m_startPoint.X - m_originalLeft));
                }
            }
        }

        // Handler for clearing element selection, adorner removal
        void Window1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (m_selected)
            {
                m_selected = false;
            }
        }

        // Handler for element selection on the canvas providing resizing adorner
        void myCanvas_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            // Remove selection on clicking anywhere the window
            if (m_selected)
            {
                m_selected = false;
            }

            // If any element except canvas is clicked, 
            // assign the selected element and add the adorner
            if (e.Source != m_selectionArea)
            {
                m_isDown = true;
                m_startPoint = e.GetPosition(m_selectionArea);

                m_selectedElement = e.Source as UIElement;

                m_originalLeft = Canvas.GetLeft(m_selectedElement);
                m_originalTop = Canvas.GetTop(m_selectedElement);

                m_selected = true;
                e.Handled = true;
            }
        }

        private void SetupAdorners()
        {
            if (m_selectionVisual == null)
                return;

            var aLayer = AdornerLayer.GetAdornerLayer(m_selectionVisual);
            
            if(m_adorner == null)
            {
                m_adorner = new ResizingAdorner(m_selectionVisual);
                m_adorner.LayoutUpdated += new EventHandler(m_adorner_LayoutUpdated);
            }

            aLayer.Remove(m_adorner);
            aLayer.Add(m_adorner);
        }

        private void m_adorner_LayoutUpdated(object sender, EventArgs e)
        {
            var selectionArea = new Rect
            {
                X = Canvas.GetLeft(m_selectionVisual)/m_selectionArea.ActualWidth,
                Y = Canvas.GetTop(m_selectionVisual)/m_selectionArea.ActualHeight,
                Width = m_selectionVisual.Width/m_selectionArea.ActualWidth,
                Height = m_selectionVisual.Height/m_selectionArea.ActualHeight
            };

            SelectionArea = selectionArea;
        }

        private void SetSelectionAreaSize()
        {
            if (m_selectionArea == null)
                return;

            //m_selectionArea.Width = TargetAreaSize.Width;
            //m_selectionArea.Height = TargetAreaSize.Height;
        }
    }
}
